use std::{borrow::Cow, fmt::Display};
use serde::Serialize;
use thiserror::Error;

pub type SqlxErr = sqlx::error::Error;

#[derive(Debug, Error)]
pub enum AppErr {

    #[error("sqlx:{0}")]
    Sqlx(#[from] SqlxErr),

    #[error("io:{0}")]
    Io(#[from] std::io::Error),

    #[error("cbor:{0}")]
    Cbor(#[from] serde_cbor::Error),

    #[error("{0}")]
    Custom(Cow<'static, str>),

    #[error("service:{0}")]
    Service(#[from] ErrInfo),
}

pub fn new_err(e: impl std::error::Error) -> AppErr {
    AppErr::Custom(Cow::Owned(e.to_string()))
}

pub fn new_err_static(msg: &'static str) -> AppErr {
    AppErr::Custom(Cow::Borrowed(msg))
}


pub trait ErrWrap<T> {
    
    fn wrap(self) -> Result<T, AppErr>;
}

impl <T, E: std::error::Error> ErrWrap<T> for Result<T, E> {

    fn wrap(self) -> Result<T, AppErr> {
        match self {
            Ok(v) => Ok(v),
            Err(e) => Err(AppErr::Custom(Cow::Owned(e.to_string())))
        }
    }
}

impl <T> ErrWrap<T> for Option<T> {

    fn wrap(self) -> Result<T, AppErr> {
        match self {
            Some(v) => Ok(v),
            None => Err(AppErr::Custom(Cow::Borrowed("option is none")))
        }
    }
}

#[derive(Debug, Error, Serialize)]
pub struct ErrInfo {
    pub err_code: i32,
    pub err_msg: Cow<'static, str>,
}


pub fn new_err_no_hex() -> AppErr {
    AppErr::Service(ErrInfo { err_code: 1, err_msg: Cow::Borrowed("没有找到对应的固件") })
}

pub fn new_err_pro_repe() -> AppErr {
    AppErr::Service(ErrInfo { err_code: 2, err_msg: Cow::Borrowed("项目名称重复") })
}

pub fn new_err_hex_repe() -> AppErr {
    AppErr::Service(ErrInfo { err_code: 3, err_msg: Cow::Borrowed("固件重复") })
}

impl Display for ErrInfo {

    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "code:{}, msg:{}", self.err_code, self.err_msg)
    }
}

